package com.umeox.watch.moto.chat.utils;

import android.annotation.SuppressLint;
import android.content.Context;
import android.media.AudioManager;
import android.media.MediaRecorder;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.umeox.moto.common.log.LogUtils;
import com.umeox.moto.common.utils.AndroidUtils;
import com.umeox.moto.common.utils.FileUtils;
import com.umeox.moto.watch.themes.util.Stopwatch;
import com.umeox.watch.moto.chat.base.BaseApp;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.concurrent.TimeUnit;

public class Recorder {

    private static final int WHAT = 100;
    private MediaRecorder mMediaRecorder;
    private static final String TAG = "Recorder";
    private long mStartMillis;
    private String mFilePath;
    private final Stopwatch mStopwatch;
    private boolean mIsRunning;
    public static final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.US);
    private OnRecorderListener mRecorderListener;

    private AudioManager mAudioManager;

    private Recorder() {
        mStopwatch = Stopwatch.createUnstarted();
        mAudioManager  = (AudioManager) BaseApp.Companion.getContext().getSystemService(Context.AUDIO_SERVICE);
    }

    public synchronized void start(int maxDurationMs) {

        try {
            mIsRunning = true;
            mStartMillis = System.currentTimeMillis();
            String fileName = AndroidUtils.getDeviceId() + "_" + mDateFormat.format(mStartMillis) + ".amr";
            mFilePath = FileUtils.getChatsCacheDir() + "/" + fileName;
            mMediaRecorder = new MediaRecorder();
            mMediaRecorder.setOnInfoListener((mr, what, extra) -> {
                if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
                    LogUtils.e("A maximum duration (" + maxDurationMs + ") had been setup and has now been reached.");
                    stop();
                }
            });
            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
            mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            mMediaRecorder.setMaxDuration(maxDurationMs);
            mMediaRecorder.setOutputFile(mFilePath);
            mMediaRecorder.prepare();
            mMediaRecorder.start();
            mStopwatch.reset();
            mStopwatch.start();
            mUpdateTimeHandler.sendEmptyMessage(WHAT);


            mAudioManager.requestAudioFocus(mAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE);

        } catch (Exception e) {
            Log.i("Recorder", "start", e);
            if (mRecorderListener != null) {
                mRecorderListener.onError(e);
            }
        }
    }

    public synchronized void stop() {
        try {
            mIsRunning = false;
            if (mMediaRecorder != null) {
                mMediaRecorder.stop();
                mMediaRecorder.release();
                mMediaRecorder = null;
            }
            mUpdateTimeHandler.removeCallbacksAndMessages(null);
            mStopwatch.stop();
            onComplete();
        } catch (Exception e) {
            Log.d(TAG, "stop: ", e);
        }

    }

    public synchronized void cancel() {
        try {
            mIsRunning = false;
            if (mMediaRecorder != null) {
                mMediaRecorder.stop();
                mMediaRecorder.release();
                mMediaRecorder = null;
            }
            mUpdateTimeHandler.removeCallbacksAndMessages(null);
            mStopwatch.stop();
            if (mFilePath != null) {
                File file = new File(mFilePath);
                if (file.exists()) {
                    file.delete();
                }
                mFilePath = null;
            }
            onComplete();

        } catch (Exception e) {

        }

    }

    private void onComplete() {
        if (mRecorderListener != null) {
            final long duration = mStopwatch.elapsed(TimeUnit.MILLISECONDS);
            mRecorderListener.onComplete(mFilePath, mStartMillis, duration);
        }

        mAudioManager.abandonAudioFocus(mAudioFocusChangeListener);
    }

    private final AudioManager.OnAudioFocusChangeListener mAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() {

        @Override
        public void onAudioFocusChange(int focusChange) {
            switch (focusChange) {
                case AudioManager.AUDIOFOCUS_LOSS:
                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                    break;
                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                    break;
                case AudioManager.AUDIOFOCUS_GAIN:
                    break;
            }

        }
    };

    public void release() {
        try {
            if (mMediaRecorder != null) {
                mMediaRecorder.stop();
                mMediaRecorder.release();
                mMediaRecorder = null;
                mIsRunning = false;
            }
        } catch (Exception e) {
            Log.e(TAG, "Recorder&release", e);
        }

        mUpdateTimeHandler.removeCallbacksAndMessages(null);
    }


    public void seRecorderListener(OnRecorderListener recorderListener) {
        mRecorderListener = recorderListener;
    }


    /**
     * 录音是否正在运行
     *
     * @return
     */
    public boolean isRunning() {
        return mIsRunning;
    }

    public interface OnRecorderListener {
        void onComplete(String filePath, long startMillis, long duration);

        void onUpdate(long duration);

        void onError(Exception e);

    }

    public static Recorder getInstance() {
        return InstanceHolder.instance;
    }

    private static class InstanceHolder {
        private final static Recorder instance = new Recorder();
    }

    private static final long INTERACTIVE_UPDATE_RATE_MS = TimeUnit.MILLISECONDS.toMillis(1000);
    @SuppressLint("HandlerLeak")
    private final Handler mUpdateTimeHandler = new Handler() {
        @Override
        public void handleMessage(Message message) {
            if (WHAT == message.what) {
                if (mRecorderListener != null) {
                    mRecorderListener.onUpdate(mStopwatch.elapsed(TimeUnit.MILLISECONDS));
                }

                mUpdateTimeHandler.sendEmptyMessageDelayed(WHAT, INTERACTIVE_UPDATE_RATE_MS);
            }
        }
    };
}
